home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Nebula 1
/
Nebula One.iso
/
Utilities
/
Workspace
/
MonsterShelf
/
Source
/
IconDragView.m
< prev
next >
Wrap
Text File
|
1995-06-12
|
12KB
|
519 lines
#import "IconDragView.h"
#import "ShelfView.h"
#import "Controller.h"
#import <appkit/appkit.h>
#import <mach/mach.h>
#import <bsd/sys/file.h>
int mouseMoved(NXPoint *o, int n, int mask);
typedef enum { Unknown, SameDeviceOperation, WriteNotAllowed, CrossDeviceOperation } DragStatus;
@implementation IconDragView : IconView
- initFrame:(const NXRect *) newFrame
image:anImage
data:(const void *) someData
andLength:(unsigned int) newLength
useSize:(BOOL) sizeValid
{
const char *const types[1] = {NXFilenamePboardType};
altImage = nil;
selected = NO;
[self registerForDraggedTypes:types count:1];
[super initFrame:newFrame image:anImage data:someData andLength:newLength
useSize:sizeValid];
return self;
}
- free
{
[altImage free];
return [super free];
}
- drawSelf:(const NXRect *) rects :(int) rectCount
{
id tempImage = image;
image = altImage ? altImage : image;
[super drawSelf:rects :rectCount];
image = tempImage;
return self;
}
- image
{
return image;
}
- getData:(void **) aPtr andLength:(unsigned int *) aLength
{
*aPtr = data;
*aLength = length;
return self;
}
- mouseDown:(NXEvent *) e
{
BOOL shift, control;
NXPoint mousePoint, offset;
unsigned int mask = NX_LMOUSEDRAGGEDMASK|NX_LMOUSEUPMASK;
NXEvent saveEvent;
BOOL newState;
shift = (e->flags & NX_SHIFTMASK) ? YES : NO;
control = (e->flags & NX_CONTROLMASK) ? YES : NO;
mousePoint = e->location;
saveEvent = *e;
[window addToEventMask:mask];
/*
* Handle selection
*/
if (shift && selected)
newState = NO;
else
newState = YES;
if (!shift && newState)
[superview deselectAll:self];
if (newState != selected) {
selected = newState;
[self display];
}
/*
* Detect drag
*/
if (mouseMoved(&mousePoint, 2, mask)) {
NXPoint imagePoint;
[self getImagePoint:&imagePoint andHilitePoint:NULL];
offset.x = mousePoint.x - e->location.x;
offset.y = mousePoint.y - e->location.y;
[self setState:NO];
[superview setDragView:self onEvent:&saveEvent withOffset:&offset
atLocation:&imagePoint];
return self;
}
/*
* If no drag, try to get workspace to do something
*/
if (selected) {
BOOL delivered = NO;
id workspace = [Application workspace];
NXPoint imageLoc, upperRight;
NXRect superRect;
NXEvent newEvent;
[self getImagePoint:&imageLoc andHilitePoint:NULL];
[self convertPoint:&imageLoc toView:nil];
[window convertBaseToScreen:&imageLoc];
imageLoc.y++; /* grody! necessary to make images line up */
[superview getFrame:&superRect];
upperRight.x = superRect.origin.x + superRect.size.width - 32;
upperRight.y = superRect.origin.y + superRect.size.height - 32;
/*
* Before animating the icon, check for double click. If we
* see a second click come in, then open the file. Otherwise,
* just select it in Workspace.
*/
if (![NXApp peekNextEvent:NX_LMOUSEDOWNMASK into:&newEvent
waitFor:0.2 threshold:NX_MODALRESPTHRESHOLD]) {
[workspace slideImage:image from:&imageLoc to:&upperRight];
delivered = [workspace selectFile:data inFileViewerRootedAt:""];
}
else {
[workspace slideImage:image from:&imageLoc to:&upperRight];
(void) [NXApp getNextEvent:NX_LMOUSEDOWNMASK];
delivered = [workspace openFile:data];
}
if (!delivered)
NXBeep();
[self setState:NO];
}
return self;
}
- (BOOL) acceptsFirstMouse
{
return YES;
}
- (BOOL) acceptsFirstResponder
{
return NO;
}
#define OPEN_DIR_ICON_FILE ".opendir.tiff"
#define DEFAULT_OPEN_DIR_FILE "/usr/lib/NextStep/Workspace.app/WM.app/openFolder.tiff"
#define OPEN_HIGHLIGHT "OpenHighlight.tiff"
- getOpenImageForDirectory:(const char *) dirname
{
struct stat st;
char buf[MAXPATHLEN];
id newImage = nil;
/*
* See if there's a .opendir.tiff
*/
strncpy(buf, dirname, sizeof(buf));
strncat(buf, "/", sizeof(buf));
strncat(buf, OPEN_DIR_ICON_FILE, sizeof(buf));
if (access(buf, R_OK) == 0) {
newImage = [[NXImage allocFromZone:[self zone]] initFromFile:buf];
if (newImage)
return newImage;
}
/*
* Before we use the default image, see if this thing is the
* root of a mounted file system, and use the appropriate icon
* if it is.
*/
if (stat(dirname, &st) >= 0 && st.st_ino == 2) {
NXSize size;
[image getSize:&size];
newImage = [[NXImage allocFromZone:[self zone]] initSize:&size];
if ([newImage lockFocus]) {
NXPoint zeroPoint = {0,0};
id highlight = [NXImage allocFromZone:[self zone]];
char buf[MAXPATHLEN];
NXBundle *bundle;
bundle = [NXBundle bundleForClass:[self class]];
if ([bundle getPath:buf forResource:OPEN_HIGHLIGHT ofType:"tiff"]) {
[highlight initFromFile:buf];
[image composite:NX_COPY toPoint:&zeroPoint];
[highlight composite:NX_SOVER toPoint:&zeroPoint];
[newImage unlockFocus];
return newImage;
}
}
}
if (access(DEFAULT_OPEN_DIR_FILE, R_OK) == 0)
newImage = [[NXImage allocFromZone:[self zone]] initFromFile:DEFAULT_OPEN_DIR_FILE];
if (newImage != nil)
return newImage;
else
return image;
}
/*
* Figure out the various parameters of the drag.
*/
- (DragStatus) dragStatusForPath:(char *) dragPath
{
char *destinationPath;
unsigned int junk;
struct stat st;
[self getData:(void **) &destinationPath andLength:&junk];
/*
* See if we should be a dragging destination. We need some way to
* make this extendible. One way would be to associate a remote
* object with the node, and ask it what it means to drag the
* incoming object over the one on the screen...
*
* For now, interpret the data as a string. Stat it to see if it's
* a directory, and if it is, say yes subject to access constraints.
*/
if (stat(destinationPath, &st) < 0 || (st.st_mode & S_IFMT) != S_IFDIR)
return WriteNotAllowed;
if (access(destinationPath, W_OK|X_OK) < 0)
return WriteNotAllowed;
/*
* Cool! We're a directory. Check the directory from which we're
* dragging, and see it's the same as this one, or if it's contained
* in this one.
*/
if (stat(destinationPath, &st) < 0)
return Unknown;
else {
dev_t destDev = st.st_dev;
ino_t destIno = st.st_ino;
if (lstat(dragPath, &st) >= 0 &&
st.st_dev == destDev && destIno == st.st_ino)
return WriteNotAllowed;
}
/*
* Handle the case where the dragging destination and the dragging
* source are on different file systems. In this case, we want to
* copy by default, not move.
*/
if (stat(destinationPath, &st) >= 0) {
dev_t destinationDevice = st.st_dev;
if (lstat(dragPath, &st) >= 0)
if (st.st_dev != destinationDevice)
return CrossDeviceOperation;
else
return SameDeviceOperation;
}
return Unknown;
}
/*
* Figure out what the drag operation should be for dragging a view onto
* another view.
*/
- (NXDragOperation) dragOperationForContext:(id <NXDraggingInfo>) dragInfo
{
NXDragOperation op = NX_DragOperationNone;
NXDragOperation maskOp = [dragInfo draggingSourceOperationMask];
id pb = [Pasteboard newName:NXDragPboard];
char *dragPath, *nextPath;
unsigned int junk;
BOOL first = YES;
[pb readType:NXFilenamePboardType data:&dragPath length:&junk];
/*
* We might have been asked to drag multiple files. Loop over all of
* them to see if they all have the same drag op. Fail if they don't!
*/
nextPath = dragPath;
do {
char path[MAXPATHLEN];
NXDragOperation thisOp = maskOp;
strncpy(path, nextPath, MAXPATHLEN);
if (index(path, '\t'))
*index(path, '\t') = '\0';
switch ([self dragStatusForPath:path]) {
case WriteNotAllowed:
case Unknown:
thisOp = NX_DragOperationNone;
break;
case CrossDeviceOperation:
if (maskOp & NX_DragOperationCopy) {
thisOp = NX_DragOperationCopy;
break;
}
/* fall through */
case SameDeviceOperation:
if (maskOp & NX_DragOperationGeneric) {
thisOp = NX_DragOperationGeneric;
break;
}
/* fall through */
default:
break;
}
/*
* Bail out of this operation isn't the same as the last one!
*/
if (first) {
op = thisOp;
first = NO;
}
else
if (op != thisOp)
return NX_DragOperationNone;
/*
* Advance to next file
*/
nextPath = index(nextPath, '\t');
if (nextPath == NULL)
break;
else
nextPath++;
} while (1);
return op;
}
/*
* Be a dragging destination...
*/
- (NXDragOperation)draggingEntered:(id <NXDraggingInfo>)sender
{
lastDragOp = [self dragOperationForContext:sender];
/*
* If we're going to do the drag, use the alternate image.
*/
if (lastDragOp != NX_DragOperationNone) {
NXSize imageSize;
altImage = [self getOpenImageForDirectory:data];
[image getSize:&imageSize];
[altImage setScalable:YES];
[altImage setSize:&imageSize];
[self display];
}
return lastDragOp;
}
- (NXDragOperation)draggingUpdated:(id <NXDraggingInfo>)sender
{
lastDragOp = [self dragOperationForContext:sender];
return lastDragOp;
}
- draggingExited:(id <NXDraggingInfo>)sender
{
/*
* Reset image to original image.
*/
[altImage free];
altImage = nil;
[self display];
[window flushWindow];
return self;
}
/*
* Eat the result...
*/
- (BOOL) prepareForDragOperation:sender
{
return YES;
}
- (BOOL) performDragOperation:(id <NXDraggingInfo>)sender
{
return YES;
}
- concludeDragOperation:(id <NXDraggingInfo>)sender
{
id workspace = [Application workspace];
id pb = [Pasteboard newName:NXDragPboard];
const char *wsmOp;
char *pbData;
unsigned int pbLength;
switch (lastDragOp) {
case NX_DragOperationGeneric:
wsmOp = WSM_MOVE_OPERATION;
break;
case NX_DragOperationLink:
wsmOp = WSM_LINK_OPERATION;
break;
case NX_DragOperationCopy:
wsmOp = WSM_COPY_OPERATION;
break;
default:
return NO;
}
[pb readType:NXFilenamePboardType data:&pbData length:&pbLength];
[workspace performFileOperation:wsmOp source:"/" destination:data
files:pbData options:NULL];
return [self draggingExited:sender];
}
- (BOOL) isOnRemovableMedia
{
struct stat st;
char *mountedList = NULL;
id workspace = [Application workspace];
if (stat(data, &st) < 0)
device = 0;
else
device = st.st_dev;
removable = NO;
if ([workspace respondsTo:@selector(getMountedRemovableMedia:)] &&
[workspace getMountedRemovableMedia:&mountedList])
[self perform:@selector(isOnRemovableDevice:) withPaths:mountedList];
if (mountedList)
free(mountedList);
return removable;
}
- isOnRemovableDevice:(const char *)path
{
struct stat st;
if (path && stat(path, &st) >= 0)
removable |= (device == st.st_dev);
return self;
}
@end
/*
* Returns true if mouse is dragged more than n pixels from 'o',
* false if the mouse button is lifted. If the mouse button is
* lifted, the mouseUp event is not consumed.
*/
int
mouseMoved(NXPoint *o, int n, int mask)
{
NXEvent e;
NXPoint p;
float dx, dy;
do {
[NXApp peekNextEvent:mask into:&e waitFor:0x7fffffff
threshold:NX_MODALRESPTHRESHOLD];
p = e.location;
if (e.type == NX_LMOUSEUP)
break;
(void) [NXApp getNextEvent:mask]; /* throw it away */
dx = abs(p.x - o->x);
dy = abs(p.y - o->y);
} while ((dy < (float) n) && (dx < (float) n));
*o = p;
return e.type != NX_LMOUSEUP;
}